package com.kotlin

import java.time.LocalDate

/**
 * 这是一个抽象类，抽象类不需要使用 open 来标注
 */
abstract class AbstractTask

/**
 * write 接口，有一个写代码的方法，子类继承需要实现此方法
 */
interface Write{
    fun writeCode()
}

/**
 * 注意子类如果要继承此类，那么 class 前需要加 open ， 否则是 final 类型的class
 */
open class Base constructor(var createDate: LocalDate) {

    // 状态字段 - 此字段子类不可重写它的值
    var status: Int? = null

    // 显示 createDate
    fun showCreateDate(): LocalDate = this.createDate

    // 注意此方法上加了 open ，那么子类就可以重写这个方法
    open fun showClassName(): String {
        return this.javaClass.name
    }

    // 注意此 方法上没有加入 open ，那么子类不可重写
    fun showSimpleClassName(): String = this.javaClass.simpleName
}

/**
 * 子类
 */
open class Person(createDate: LocalDate, var username: String = "张三") : Base(createDate) {

    /**
     * 重写父类的 showClassName 方法
     *
     * 注意：
     *  1、此类上增加了 final 修饰，那么意味着子类不可在重写此方法
     *  2、使用 super 关键字调用父类方法
     */
    final override fun showClassName(): String {
        return "子类重写父类的 showClassName 方法，调用父类的showClassName方法的结果为:${super.showClassName()}"
    }

    // override fun showSimpleClassName() : String{
    //     return "不可重写，因为父类的方法声明上没有open关键字"
    // }


    inner class Child {
        fun name() {
            println("内部类访问外部类的方法：" + super@Person.showClassName())
        }
    }
}

/**
 * 此类实现了 Write 接口，但是没有实现writeCode方法，是因为 实现接口时使用 by writer 及代理给了传递参数中的writer去实现
 */
class Worker(createDate: LocalDate,username: String,write: Write) : Person(createDate,username),Write by write

/**
 * 这意味着，基类构造函数执行时，派生类中声明或覆盖的属性都还没有初始化。
 * 如果在基类初始化逻辑中（直接或通过另一个覆盖的 open 成员的实现间接）使用了任何一个这种属性，
 * 那么都可能导致不正确的行为或运行时故障。设计一个基类时，应该避免在构造函数、属性初始化器以及 init 块中使用 open 成员。
 */
open class BaseClz(val name: String) {

    init {
        println("Initializing Base")
    }

    open val size: Int =
        name.length.also { println("Initializing size in Base: $it") }
}

class Derived(
    name: String,
    val lastName: String
) : BaseClz(name.capitalize().also { println("Argument for Base: $it") }) {

    init {
        println("Initializing Derived")
    }

    override val size: Int =
        (super.size + lastName.length).also { println("Initializing size in Derived: $it") }
}



fun main() {
    var person = Person(LocalDate.now(), "李四")
    println(person.username)
    println(person.showClassName())

    var derived = Derived(name = "admin", lastName = "李四")
    println(derived.lastName)
    println(derived.name)

    // 测试内部类调用外部类的方法
    Person(LocalDate.now()).Child().name()
}
